package com.yao.mssm.aspect;

import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;

import com.yao.mssm.annotation.DataSource;
import com.yao.mssm.config.DynamicDataSourceHolder;
import com.yao.mssm.config.properties.DBType;

@Component
@EnableAspectJAutoProxy(proxyTargetClass=true)
@Aspect
public class DataSourceAspect {
	
	private final static Logger logger = LoggerFactory.getLogger(DataSourceAspect.class);

	/**指定切入点表达式，拦截那些方法，即为那些类生成代理对象
	 * 拦截目标方法，获取datasource注解中的数据源。
	 * 
	 */
	@Pointcut("target(com.baomidou.mybatisplus.service.IService)")
	public void pointcut(){}
	
    /**
     * 拦截目标方法，获取由@DataSource指定的数据源标识，设置到线程存储中以便切换数据源
     * 
     * @param point
     * @throws Exception
     */
	@Before("pointcut()")
    public void intercept(JoinPoint point) throws Exception {
		
        Class<?> target = point.getTarget().getClass();
        MethodSignature signature = (MethodSignature) point.getSignature();
        // 默认使用目标类型的注解，如果没有则使用其实现接口的注解
        for (Class<?> clazz : target.getInterfaces()) {
            resolveDataSource(clazz, signature.getMethod());
        }
        resolveDataSource(target, signature.getMethod());
    }
	/**
	 * 还原原数据源
	 * @param point
	 * @throws Exception
	 */
	@After("pointcut()")
	public void after() throws Exception {
		DynamicDataSourceHolder.setDataSource(DBType.DEFAULT_SOURCE);
		logger.info("*************************数据源切换为:"+DBType.DEFAULT_SOURCE);
	}

    /**
     * 提取目标对象方法注解和类型注解中的数据源标识
     * 
     * @param clazz
     * @param method
     */
    private void resolveDataSource(Class<?> clazz, Method method) {
        try {
            Class<?>[] types = method.getParameterTypes();
            // 默认使用类型注解
            if (clazz.isAnnotationPresent(DataSource.class)) {
                DataSource source = clazz.getAnnotation(DataSource.class);
                DynamicDataSourceHolder.setDataSource(source.value());
                logger.info("*************************数据源切换为:"+source.value());
            }
            // 方法注解可以覆盖类型注解
            Method m = clazz.getMethod(method.getName(), types);
            if (m != null && m.isAnnotationPresent(DataSource.class)) {
                DataSource source = m.getAnnotation(DataSource.class);
                DynamicDataSourceHolder.setDataSource(source.value());
                logger.info("*************************数据源切换为:"+source.value());
            }
        } catch (Exception e) {
        	logger.info(clazz + ":" + e.getMessage());
        }
    }
    

}